﻿using AngleSharp.Attributes;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using NewRetail.Application.Components.Goods.Model;
using NewRetail.Application.Components.Platform.Entity;
using NewRetail.Application.Components.WeChat.CardVoucher.Model;
using NewRetail.Application.Components.WeChat.Member.Services;
using NewRetail.Application.Core;
using NewRetail.Application.Core.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Uow;


namespace NewRetail.Application.Worker
{
    //用户积分同步到微信会员卡并更新库里状态
    public class MemberIntegralSyncWechatWorker : ApplicationService, ITransientDependency
    {
        #region params
        private readonly IHttpContextAccessor _accessor;
        private readonly ILogger _logger;
        protected IEntityHelper _entityHelper => this.LazyServiceProvider.LazyGetRequiredService<IEntityHelper>();
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly RedLockFactoryWrapper _redLockFactoryWrapper;
        public readonly IMemberService _wechatMemberService;
        private readonly IRepository<PosIntegral> _posIntegralRepository;
        #endregion

        #region 构造
        public MemberIntegralSyncWechatWorker(IHttpContextAccessor accessor, ILogger<DashboardRefreshingWorker> logger, 
            RedLockFactoryWrapper redLockFactoryWrapper,
            IMemberService wechatMemberService, IRepository<PosIntegral> posIntegralRepository, IUnitOfWorkManager unitOfWorkManager)
        {
            _accessor = accessor;
            _logger = logger;
            _redLockFactoryWrapper = redLockFactoryWrapper;
            _unitOfWorkManager = unitOfWorkManager;
            _wechatMemberService = wechatMemberService;
            _posIntegralRepository = posIntegralRepository;
        }
        #endregion

        #region method
        [UnitOfWork]
        public virtual async Task Execute()
        {
            try
            {
                _logger.LogInformation(DateTime.Now.ToString() + "：同步微信会员积分数据开始...................");
                IList<Task> tasks = new List<Task>();
                Task task = TrySyncMemberIntegralWechatAsync();
                tasks.Add(task);
                await Task.WhenAll(tasks);

            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                throw;
            }
        }
        #endregion

        #region 同步会员积分到微信
        [UnitOfWork]
        private async Task TrySyncMemberIntegralWechatAsync(CancellationToken cancellationToken = default)
        {
            // resource 锁定的对象
            // expiryTime 锁定过期时间，锁区域内的逻辑执行如果超过过期时间，锁将被释放
            // waitTime 等待时间,相同的 resource 如果当前的锁被其他线程占用,最多等待时间
            // retryTime 等待时间内，多久尝试获取一次
            using var distributedLock = await _redLockFactoryWrapper.RedLockFactory.CreateLockAsync(
                resource: $"{nameof(DashboardRefreshingWorker)}",
                expiryTime: TimeSpan.FromMinutes(1),
                waitTime: TimeSpan.FromMinutes(1),
                retryTime: TimeSpan.FromSeconds(3));

            if (distributedLock.IsAcquired)
            {
                var db = await _posIntegralRepository.GetDbContextAsync();
                var posUploadIntegrals = await db.Set<PosIntegral>().AsNoTracking().Where(x => x.isUpload == true)?.ToListAsync();
                var posDealUploadIntegrals = posUploadIntegrals?.GroupBy(g => g.memberID).Select(x => new PosIntegral()
                {
                    memberID = x.Key,
                    integral = x.Sum(s => s.plusOrMinus == true ? s.integral : -s.integral)
                })?.ToList();
                //未上传的会员积分.重试次数小于3的，大于3就临时丢弃，防止一直在刷新数据
                var posIntegrals = await db.Set<PosIntegral>().AsNoTracking().Where(x => x.isUpload == false && x.retryCount < 3)?.ToListAsync();
                if (posIntegrals != null)
                {
                    var memberIdList = posIntegrals.GroupBy(x => x.memberID).Select(x => x.Key).ToList();
                    //遍历每个会员
                    foreach(var mItem in memberIdList)
                    {
                        using var uow = _unitOfWorkManager.Begin(requiresNew: true, isTransactional: true);
                        try
                        {
                            //根据会员Id获取openId
                            var memberInfo = await db.Set<PosMember>().AsNoTracking().Where(x => x.Id == mItem)?.FirstOrDefaultAsync();

                            var currMemberPosIntegrals = posIntegrals.Where(x => x.memberID == mItem).OrderBy(x => x.operateTime).ToList();
                            //遍历当前会员每条积分明细用于同步
                            foreach (var item in currMemberPosIntegrals)
                            {
                                //openid存在才做同步
                                if (memberInfo != null && !string.IsNullOrWhiteSpace(memberInfo.openId))
                                {
                                    //已经上传的积分
                                    var haveUploadBonus = posDealUploadIntegrals.Where(x => x.memberID == mItem)?.FirstOrDefault()?.integral ?? 0;
                                    //当前需要上传的积分
                                    var needUploadBonus = item.plusOrMinus ? item.integral : -item.integral;
                                    var integralData = new UpdateWeChatUserMemberCardInputDto()
                                    {
                                        OpenId = memberInfo.openId,
                                        Bounus = Convert.ToInt32(haveUploadBonus) + Convert.ToInt32(needUploadBonus),
                                        ModifiedBounus = Convert.ToInt32(needUploadBonus),
                                        ModifiedBounusRecord = item.integralSource
                                    };
                                    var operateResult = await _wechatMemberService.UpdateWeChatUserMemberCardAsync(integralData);
                                    if (!string.IsNullOrEmpty(operateResult.Item2))
                                    {
                                        _logger.LogError("任务同步微信会员积分失败:" + operateResult.Item2);
                                        item.retryCount++;
                                        item.updateTime = DateTime.Now;
                                        _entityHelper.SetUpdationInfo(item);
                                        await _posIntegralRepository.UpdateAsync(item);
                                    }
                                    else
                                    {
                                        //更新本地上传状态
                                        item.isUpload = true;
                                        item.updateTime = DateTime.Now;
                                        _entityHelper.SetUpdationInfo(item);
                                        await _posIntegralRepository.UpdateAsync(item);

                                        //更新成功后需要将已经上传的重新计算
                                        //获取对象是否存在
                                        var tIntegral = item.plusOrMinus == true ? item.integral : -item.integral;
                                        var gIndex = !posDealUploadIntegrals.Any() ? -1 : posDealUploadIntegrals.FindIndex(x => x.memberID == mItem);
                                        if (gIndex < 0)
                                        {
                                            var hUI = new PosIntegral()
                                            {
                                                memberID = item.memberID,
                                                integral = tIntegral
                                            };
                                            if (!posDealUploadIntegrals.Any())
                                                posDealUploadIntegrals = new List<PosIntegral>() { hUI };
                                            else
                                                posDealUploadIntegrals.Add(hUI);
                                        }
                                        else
                                        {
                                            
                                            posDealUploadIntegrals.ToList()[gIndex].integral += tIntegral;
                                        }
                                    }
                                }
                            }
                            await db.SaveChangesAsync();

                            await uow.CompleteAsync();
                        }
                        catch (Exception e)
                        {
                            await uow.RollbackAsync();
                            _logger.LogError(message: e.Message, exception: e);
                        }
                    }
                }
                    
                _logger.LogInformation(DateTime.Now.ToString() + "：同步微信会员积分数据结束...................");
            }
            else
            {
                _logger.LogInformation("未能拿到锁，存在并发");
            }
        }
        #endregion
    }
}
